﻿#region 참조 네임스페이스

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.XPath;

#endregion

namespace Skying.Reflection.Update.Extension.AdobeAir
{
	/// <summary>
	/// Adobe AIR 어플리케이션의 버전 정보를 점검할 수 있는 메서드를 제공한다.
	/// </summary>
	class ApplicationChecker
	{
		#region 상수

		/// <summary>
		/// 어플리케이션 설정 정보 파일명 상수를 나타낸다.
		/// </summary>
		private const string _APPLICATION_XML_FILE_NAME = "application.xml";

		/// <summary>
		/// Adobe AIR 어플리케이션 XML 파일의 네임스페이스 상수를 나타낸다.
		/// </summary>
		private const string _APPLICATION_XML_NAMESPACE = "http://ns.adobe.com/air/application/3.1";

		private static readonly string _APPLICATION_XML_PATH;

		#endregion

		#region 생성자/소멸자

		static ApplicationChecker()
		{
			_APPLICATION_XML_PATH = string.Format(@"{0}\{1}\{2}\{3}",
				Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
				UpdateManager._UPDATE_MANAGER_GUID,
				typeof(ApplicationChecker).Name,
				_APPLICATION_XML_FILE_NAME);
		}

		#endregion

		#region 업데이트 점검

		/// <summary>
		/// Adobe AIR 애플리케이션을 실행한다.
		/// </summary>
		public static void ExecuteApplication()
		{
			if (!File.Exists(_APPLICATION_XML_PATH)) return;

			XPathDocument document = new XPathDocument(_APPLICATION_XML_PATH);

			XPathNavigator rootNavigator = document.CreateNavigator();

			XmlNamespaceManager namespaceManager = new XmlNamespaceManager(rootNavigator.NameTable);

			namespaceManager.AddNamespace("ns", _APPLICATION_XML_NAMESPACE);

			XPathNavigator fileNameNavigator = rootNavigator.SelectSingleNode("//ns:filename", namespaceManager);

			string executeFilePath = string.Format(@"{0}\{1}.exe", Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), fileNameNavigator.Value);

			// AIR 애플리케이션의 실행 파일이 실제로 존재하는 경우에만 실행한다.
			if (File.Exists(executeFilePath))
			{
				Process.Start(executeFilePath);
			}
		}

		/// <summary>
		/// Adobe AIR 어플리케이션의 버전 정보를 비교하여 업데이트가 필요한지를 점검한다.
		/// </summary>
		/// <param name="applicationStream">다운로드된 업데이트 체크 정보의 <see cref="System.IO.Stream"/>객체를 설정한다.</param>
		public static bool Check(Stream applicationStream)
		{
			bool required = false;

			try
			{
				if (!Directory.Exists(Path.GetDirectoryName(_APPLICATION_XML_PATH)))
				{
					Directory.CreateDirectory(Path.GetDirectoryName(_APPLICATION_XML_PATH));
				}

				string oldVersionNumber = string.Empty;

				// 로컬에 저장된 업데이트 체크 정보가 존재하는 경우, 버전 정보를 읽어들인다.
				if (File.Exists(_APPLICATION_XML_PATH))
				{
					XPathDocument oldDocument = new XPathDocument(_APPLICATION_XML_PATH);

					XPathNavigator oldRootNavigator = oldDocument.CreateNavigator();

					XmlNamespaceManager namespaceManager = new XmlNamespaceManager(oldRootNavigator.NameTable);

					namespaceManager.AddNamespace("ns", _APPLICATION_XML_NAMESPACE);

					XPathNavigator oldVersionNavigator = oldRootNavigator.SelectSingleNode("//ns:versionNumber", namespaceManager);

					oldVersionNumber = oldVersionNavigator.Value;
				}

				XPathDocument document = new XPathDocument(applicationStream);

				XPathNavigator rootNavigator = document.CreateNavigator();

				XmlNamespaceManager nsManager = new XmlNamespaceManager(rootNavigator.NameTable);

				nsManager.AddNamespace("ns", _APPLICATION_XML_NAMESPACE);

				XPathNavigator versionNavigator = rootNavigator.SelectSingleNode("//ns:versionNumber", nsManager);

				// 다운로드 받은 업데이트 체크 정보로부터 버전 정보를 가져온다.
				string versionNumber = versionNavigator.Value;

				// 다운로드 받은 버전 정보와 로컬 버전 정보를 서로 비교한다.
				required = versionNumber.CompareTo(oldVersionNumber) > 0;

				// 업데이트가 필요한 경우, 업데이트 체크 정보 스트림을 로컬에 저장한다.
				if (required)
				{
					using (XmlTextWriter writer = new XmlTextWriter(_APPLICATION_XML_PATH, Encoding.UTF8))
					{
						writer.Formatting = Formatting.Indented;
						writer.Indentation = 4;

						writer.WriteStartDocument();
						writer.WriteNode(rootNavigator, true);
						writer.WriteEndDocument();

						writer.Close();
					}
				}
			}
			catch (Exception error)
			{
				throw error;
			}

			// 읽어들인 버전 정보가 설치된 버전 정보보다 새로운 버전인 경우, 업데이트를 하도록 true를 반환한다.
			return required;
		}

		#endregion
	}
}